#include "drv_serial_stm32f4xx.h"

void stm32f411x_uart_gpio_init(struct stm32f411x_uart_data *port)
{
    LL_GPIO_InitTypeDef   GPIO_InitStruct  = {0};
    
	LL_AHB1_GRP1_EnableClock(port->txd->clock);
    LL_AHB1_GRP1_EnableClock(port->rxd->clock);
    
    GPIO_InitStruct.Pin   = port->txd->pin;
    GPIO_InitStruct.Mode  = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull       = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate  = port->txd->alternate;
    LL_GPIO_Init(port->txd->port, &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin   = port->rxd->pin;
    GPIO_InitStruct.Alternate  = port->rxd->alternate;
    LL_GPIO_Init(port->rxd->port, &GPIO_InitStruct);
}	
	
int stm32f411x_uart_data(struct hal_serial_s *serial,struct hal_serial_cfg_s *cfg)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
    LL_USART_InitTypeDef  USART_InitStruct = {0};
	
	if(port->enable_clock != NULL){
		port->enable_clock(port->clock);
	}else{
		return -1;
	}
    
    USART_InitStruct.BaudRate   = cfg->buad_rate;

    if (cfg->data_bits == DATA_BITS_8)
        USART_InitStruct.DataWidth  = LL_USART_DATAWIDTH_8B;

    if (cfg->stop_bits == STOP_BITS_1)
        USART_InitStruct.StopBits   = LL_USART_STOPBITS_1;
    else if (cfg->stop_bits == STOP_BITS_2)
        USART_InitStruct.StopBits   = LL_USART_STOPBITS_2;
    
    if(cfg->parity == PARITY_EVEN)
        USART_InitStruct.Parity     = LL_USART_PARITY_EVEN;
    else if(cfg->parity == PARITY_ODD)
        USART_InitStruct.Parity     = LL_USART_PARITY_ODD;
    else 
        USART_InitStruct.Parity     = LL_USART_PARITY_NONE;
    
    USART_InitStruct.TransferDirection   = LL_USART_DIRECTION_TX_RX;
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    USART_InitStruct.OverSampling        = LL_USART_OVERSAMPLING_16;
	
	LL_USART_Disable(port->USARTx);
    LL_USART_Init(port->USARTx, &USART_InitStruct);
    LL_USART_ConfigAsyncMode(port->USARTx);
	LL_USART_Enable(port->USARTx);
    
	return 0;
}
static void stm32f411x_irq_config(struct hal_serial_s *serial)
{   
    struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;

    NVIC_SetPriority(port->irq, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),port->irq_pre_pri, port->irq_sub_pri));
    NVIC_EnableIRQ(port->irq);
	
	LL_USART_DisableIT_TXE(port->USARTx);
    LL_USART_DisableIT_TC(port->USARTx);
    LL_USART_DisableIT_RXNE(port->USARTx);
	/* clear interrupt */
    LL_USART_ClearFlag_RXNE(port->USARTx);
	/* clear interrupt */
    LL_USART_ClearFlag_TC(port->USARTx);
}

int stm32f4_uart_init(struct hal_serial_s *serial)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
	LL_USART_InitTypeDef  USART_InitStruct = {0};
	
	stm32f411x_uart_gpio_init(port);
	stm32f411x_uart_data(serial,&serial->cfg);
	
	if(port->enable_clock != NULL){
		port->enable_clock(port->clock);
	}else{
		return -1;
	}
    
    USART_InitStruct.BaudRate   = serial->cfg.buad_rate;
    if (serial->cfg.data_bits == DATA_BITS_8)
        USART_InitStruct.DataWidth  = LL_USART_DATAWIDTH_8B;
    if (serial->cfg.stop_bits == STOP_BITS_1)
        USART_InitStruct.StopBits   = LL_USART_STOPBITS_1;
    else if (serial->cfg.stop_bits == STOP_BITS_2)
        USART_InitStruct.StopBits   = LL_USART_STOPBITS_2;
    if(serial->cfg.parity == PARITY_EVEN)
        USART_InitStruct.Parity     = LL_USART_PARITY_EVEN;
    else if(serial->cfg.parity == PARITY_ODD)
        USART_InitStruct.Parity     = LL_USART_PARITY_ODD;
    else 
        USART_InitStruct.Parity     = LL_USART_PARITY_NONE;
    
    USART_InitStruct.TransferDirection   = LL_USART_DIRECTION_TX_RX;
    USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    USART_InitStruct.OverSampling        = LL_USART_OVERSAMPLING_16;
    LL_USART_Init(port->USARTx, &USART_InitStruct);
    LL_USART_ConfigAsyncMode(port->USARTx);
	stm32f411x_irq_config(serial);
	
	LL_USART_Enable(port->USARTx);

	return 0;
}

int stm32f4_putc(struct hal_serial_s *serial,char ch)
{
    struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
	
	while(!LL_USART_IsActiveFlag_TXE(port->USARTx));
    LL_USART_TransmitData8(port->USARTx,ch);
	return 1;
}

int stm32f4_getc(struct hal_serial_s *serial,char *ch)
{
    struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET)
    {
        *ch = LL_USART_ReceiveData8(port->USARTx);
        port->new_data_from_int = 0;
		return 1;
    }
    
	if(port->new_data_from_int & 0x10000000){
		*ch = port->new_data_from_int & 0x00000ff;
		port->new_data_from_int = 0;
		return 1;
	}
	return 0;
}

void stm32f4_enable_irq(struct hal_serial_s *serial,int irq)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
	if(irq == SERIAL_INT_TXDONE){
        LL_USART_EnableIT_TC(port->USARTx);
	}else if(irq == SERIAL_INT_RXDONE){
		LL_USART_EnableIT_RXNE(port->USARTx);
	}else if(irq == SERIAL_INT_DMATXDONE){
		/*  not support for now */
	}
}

void stm32f4_disable_irq(struct hal_serial_s *serial,int irq)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)serial->priv;
	if(irq == SERIAL_INT_TXDONE){
		LL_USART_DisableIT_TC(port->USARTx);
	}else if(irq == SERIAL_INT_RXDONE){
		LL_USART_DisableIT_RXNE(port->USARTx);
	}else if(irq == SERIAL_INT_DMATXDONE){
		/*  not support for now */
	}
}


struct stm32f411x_uart_data  *uart_data[6];
struct hal_serial_s          *stm32_serial[6];

void stm32f4_serial_register(char *name,struct hal_serial_s *serial,struct stm32f411x_uart_data *uart)
{	
	
	serial->putc         = stm32f4_putc;
	serial->getc         = stm32f4_getc;
	serial->enable_irq   = stm32f4_enable_irq;
	serial->disable_irq  = stm32f4_disable_irq; 
	serial->init         = stm32f4_uart_init;
	serial->configure    = stm32f411x_uart_data;
	serial->cfg          = serial_defauhal_cfg;
	serial->priv         = uart;
	
	if(uart->USARTx == USART1){
		stm32_serial[0] = serial;
	}
	
	if(uart->USARTx == USART2){
		stm32_serial[1] = serial;
	}
	
	if(uart->USARTx == USART3){
		stm32_serial[2] = serial;
	}
	
	if(uart->USARTx == UART4){
		stm32_serial[3] = serial;
	}
	
	if(uart->USARTx == UART5){
		stm32_serial[4] = serial;
	}
	
	if(uart->USARTx == USART6){
		stm32_serial[5] = serial;
	}
	
	
	serial_device_register(serial,name,HAL_DEV_INT_RX | HAL_DEV_INT_TX | HAL_DEV_RDWR);
}


void USART1_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[0]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[0], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[0], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}


void USART2_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[1]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[1], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[1], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}


void USART3_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[2]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[2], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[2], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}

void UART4_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[3]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[3], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[3], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}

void UART5_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[4]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[4], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[4], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}

void USART6_IRQHandler(void)
{
	struct stm32f411x_uart_data *port = (struct stm32f411x_uart_data *)stm32_serial[5]->priv;
    
	/* enter interrupt */
    //hal_enter_interrupt();
	
    if(LL_USART_IsActiveFlag_RXNE(port->USARTx) != RESET){
        port->new_data_from_int  = 0x10000000;
		port->new_data_from_int |= (LL_USART_ReceiveData8(port->USARTx) & 0x0000ffff);
        serial_isr(stm32_serial[5], SERIAL_INT_RXDONE);
        LL_USART_ClearFlag_RXNE(port->USARTx);
    }
    
    if(LL_USART_IsActiveFlag_TC(port->USARTx) != RESET){
        serial_isr(stm32_serial[5], SERIAL_INT_TXDONE);
        LL_USART_ClearFlag_TC(port->USARTx);
    }

    /* exit interrupt */
    //hal_exit_interrupt();
}



